
export default class WxLoginUtils {
    private static instance: WxLoginUtils;

    public static getInstance() {
        if (!this.instance) {
            this.instance = new WxLoginUtils();
        }
        return this.instance;
    }

    private mWxPlus: ApicloudModules['wxPlus'];

    private constructor() {
        this.mWxPlus = api.require('wxPlus');
        if (!this.mWxPlus) {
            throw new Error('wxPlus 模块未引入');
        }
    }

    /**
     * 判断是否安装微信
     * 
     */
    public isInstalled() {
        return new Promise((res) => {
            this.mWxPlus.isInstalled((ret) => {
                res(ret && ret.installed);
            });
        });
    }
    /**
     * 获取WXCODE
     * @param params 
     * @returns {status:boolean} 获取成功status为true
     */
    public async getWxCode(params: {
        apiKey?: string;
        scope?: string;
    } = {}): Promise<{ status: boolean, code: string, msg: string }> {
        return new Promise((res) => {
            this.mWxPlus.auth(params, (ret, err) => {
                if (ret.status) {
                    res({
                        status: true,
                        code: ret.code,
                        msg: '获取成功'
                    });
                } else {
                    const errMsgs = ['成功，用户同意', '取消登录', '用户拒绝授权', '当前设备未安装微信客户端'];
                    const msg = errMsgs[err.code] || '未知错误';
                    res({
                        status: false,
                        msg,
                        code: ''
                    });
                }
            });
        });
    }
    /**
     * 获取OPEN_ID
     * @param params 
     * @returns {status:boolean} 获取成功status为true
     */
    public async getWxTokenAndOpenId(params: {
        apiKey?: string;
        scope?: string;
        code: string;
    }): Promise<{ status: boolean, openId: string, accessToken: string, msg: string }> {

        return new Promise((res) => {
            this.mWxPlus.getToken(params, (ret, err) => {
                if (ret.status) {
                    res({
                        status: true,
                        openId: ret.openId,
                        accessToken: ret.accessToken,
                        msg: '获取成功'
                    });
                } else {
                    const errMsgs = ['成功', 'apiKey值为空或非法', 'apiSecret值为空或非法', 'code值为空或非法', '网络超时'];
                    const msg = errMsgs[err.code] || '未知错误';
                    res({
                        status: false,
                        openId: '',
                        accessToken: '',
                        msg
                    });
                }
            });
        });
    }

    /**
    * 获取用户信息
     * @returns {status:boolean} 获取成功status为true
    */
    public async getWxUserInfo(params: {
        accessToken: string;
        openId: string;
        lang?: 'zh_CN' | 'zh_TW' | 'en'
    }): Promise<{
        status: boolean,
        openid: string,
        nickname: string,
        sex: 1 | 2,
        headimgurl: string,
        privilege: string[],
        unionid: string,
        msg: string
    }> {
        return new Promise((res) => {
            this.mWxPlus.getUserInfo(params,
                (ret, err) => {
                    if (ret.status) {
                        res(Object.assign(ret, { msg: '获取成功' }));
                    } else {
                        const errMsgs = ['成功', 'accessToken 过期', 'openId非法', 'openId值为空', 'accessToken值为空', 'accessToken非法', '网络超时'];
                        const msg = errMsgs[err.code] || '未知错误';
                        res(<any>{
                            status: false,
                            msg
                        });
                    }
                });
        });

    }

    /**
     * 调用微信登录
     * @param params 
     * @returns {status:boolean} 登录成功status为true
     */
    public async login(params: {
        apiKey?: string;
        scope?: string;
        lang?: "zh_CN" | "zh_TW" | "en" | undefined;
    } = {}): Promise<{
        status: boolean,
        msg: string,
        openid: string,
        nickname: string,
        sex: 1 | 2,
        headimgurl: string,
        privilege: string[],
        unionid: string,
    }> {
        const codeData = await this.getWxCode(params);
        if (!codeData.status) {
            return <any>codeData;
        }
        const openIdData = await this.getWxTokenAndOpenId({
            ...params,
            code: codeData.code
        });
        if (!openIdData.status) {
            return <any>openIdData;
        }
        const infoData = await this.getWxUserInfo({
            accessToken: openIdData.accessToken,
            openId: openIdData.openId,
            lang: params.lang
        });
        return infoData;

    }

    /**
     * 订阅一次微信消息
     * @param params 
     * @param callback 
     */
    public subscribeMsg(params: {
        apiKey: string,
        scene: number,
        templateId: string,
        reserved?: string
    }): Promise<{
        status: boolean,
        eventType: 'start' | 'error' | 'back' | 'backError',
        templateId: string,
        action: string,
        openId: string,
        reserved: string,
        scene: number,
        msg: string
    }> {
        return new Promise((res) => {
            this.mWxPlus.subscribeMsg(params, (ret, err) => {
                if (ret) {
                    // 模块有问题,有时会少个字母 p
                    if (ret.eventTye) {
                        ret.eventType = ret.eventTye;
                    }
                    if (ret.eventType === 'back') {
                        res(Object.assign(ret, { msg: '订阅成功', status: true }));
                    } else if (ret.eventType === 'error' || ret.eventType === 'backError') {
                        res(Object.assign(ret, { msg: '订阅失败', status: false }));
                    }
                } else {
                    const errMsgs = ['成功', 'templateId为空', '用户取消', '发送失败', '授权拒绝', '微信服务器返回的不支持错误', '未知错误', '注册SDK失败'];
                    const msg = errMsgs[err.code] || '未知错误';
                    res(<any>{
                        status: false,
                        msg
                    });
                }
            });
        });
    }
}

